#include <unordered_map>
#include <functional>
#include "vertex_layout.h"
#include "framework/logger.h"

namespace cyb
{

static std::unordered_map<VertexLayout::Type, uint8_t> s_attributeTypeSize = {
	{ VertexLayout::Type::Uint8,		1 },
	{ VertexLayout::Type::Uint16,		2 },
	{ VertexLayout::Type::HalfFloat,	3 },
	{ VertexLayout::Type::Float,		4 }
};

std::string AttributeToString( const VertexLayout::Attribute attribute )
{
	switch ( attribute )
	{
	case VertexLayout::Attribute::Position:		return "a_position";
	case VertexLayout::Attribute::Normal:		return "a_normal";
	case VertexLayout::Attribute::Color0:		return "a_color0";
	case VertexLayout::Attribute::Color1:		return "a_color1";
	case VertexLayout::Attribute::Indices:		return "a_indices";
	case VertexLayout::Attribute::TexCoord0:	return "a_texcoord0";
	case VertexLayout::Attribute::TexCoord1:	return "a_texcoord1";
	case VertexLayout::Attribute::TexCoord2:	return "a_texcoord2";
	case VertexLayout::Attribute::TexCoord3:	return "a_texcoord3";
	default: break;
	}

	return "error";
}

std::string AttributeTypeToString( const VertexLayout::Type type )
{
	switch ( type )
	{
	case VertexLayout::Type::Uint8:				return "Uint8";
	case VertexLayout::Type::Uint16:			return "Uint16";
	case VertexLayout::Type::HalfFloat:			return "HalfFloat";
	case VertexLayout::Type::Float:				return "Float";
	default: break;
	}

	return "error";
}

VertexLayout::Entry::Entry( Attribute attribute, uint8_t size, Type type, bool normalized )
{
	m_attribute = attribute;
	m_size = size;
	m_type = type;
	m_normalized = normalized;
}

VertexLayout::VertexLayout( const VertexLayout::InitList& init ) :
	m_layout( init )
{
	m_hash = 0;
	m_stride = 0;

	for ( auto& attribute : m_layout )
	{
		attribute.m_offset = m_stride;
		m_stride += s_attributeTypeSize[attribute.m_type] * attribute.m_size;
		m_hash ^= std::hash<VertexLayout::Attribute>()( attribute.m_attribute );
	}
}

uint32_t VertexLayout::Hash() const
{
	return m_hash;
}

uint32_t VertexLayout::Stride() const
{
	return m_stride;
}

const std::vector<VertexLayout::Entry>& VertexLayout::Layout() const
{
	return m_layout;
}

void VertexLayout::Print() const
{
	CYB_DEBUG( "Created a new vertex layout with hash 0x", std::hex, Hash(), ":" );
	for ( auto& attribute : m_layout )
	{
		CYB_DEBUG( "\t", AttributeToString( attribute.m_attribute ), " ", (int) attribute.m_size, " ", AttributeTypeToString( attribute.m_type ), attribute.m_normalized ? " normalized" : "" );
	}
}

}	// namespace cyb